package com.egao.common.component.minio.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.egao.common.component.minio.config.MinioBucket;
import com.egao.common.component.minio.config.MinioConfig;
import com.egao.common.core.exception.ParameterException;
import com.egao.common.core.web.JsonResult;
import io.minio.MinioClient;
import io.minio.http.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Minio 上传服务
 *
 * @author lym
 */
@Service
public class MinioService {

    @Autowired
    private MinioConfig minioConfig;

    /**
     * 合法文件后缀名 字符串逗号分隔
     */
    @Value("${minio.suffixs}")
    private String suffixs;

    @Value("${minio.endpoint}")
    private String endpoint;

    private final Logger logger = LoggerFactory.getLogger(MinioService.class.getName());

    /**
     * 上传文件到Minio存储桶
     * 上传到参数存储桶当前日期文件夹下
     *
     * @param file   文件
     * @param bucket 存储桶名称
     * @return url访问路径 name文件名称
     */
    public JsonResult uploadBucket(MultipartFile file, String bucket) {
        if (file == null) {
            throw new ParameterException("上传失败：上传文件错误");
        }

        if (StrUtil.isBlank(bucket)) {
            throw new ParameterException("上传失败：上传存储错误");
        }

        try {
            MinioClient minioClient = minioConfig.minioClient();

            // 文件名称
            String fileName = file.getOriginalFilename();

            // 文件类型
            String suffixName = fileName.substring(fileName.lastIndexOf("."));

            // 验证文件格式
            if (!verifySuffix(suffixName)) {
                return JsonResult.error("上传失败：上传文件不合法");
            }

            // 新文件名
            String objectName = IdUtil.simpleUUID() + suffixName;

            // 文件类型
            String fileType = file.getContentType();

            // 日期路径(当前日期)
            String datePath = DateUtil.format(new Date(), "yyyy/MM/dd");

            // 路径 + 文件对象
            String path = datePath + "/" + objectName;

            // 上传
            minioClient.putObject(bucket, path, file.getInputStream(), fileType);

            // 获取文件URL
            String url = minioClient.getObjectUrl(bucket, path);

            // 获取文件临时URL
            String preview = minioClient.getPresignedObjectUrl(Method.GET, bucket, path, 600, new HashMap<>());

            return JsonResult.ok("上传成功").put("url", url)
                    .put("preview", preview)
                    .put("path", path)
                    .put("name", fileName);
        } catch (Exception e) {
            logger.error("MINIO ERROR", e);
            return JsonResult.error("上传异常");
        }
    }

    /**
     * 上传文件到Minio默认存储桶
     * 上传到默认存储桶+路径参数+当前日期文件夹下
     *
     * @param file 文件
     * @param path 存储路径 以/开头 例：/files/pdf
     * @return url访问路径 name文件名称
     */
    public JsonResult uploadPath(MultipartFile file, String path) {
        if (file == null) {
            throw new ParameterException("上传失败：上传文件错误");
        }

        if (StrUtil.isBlank(path)) {
            throw new ParameterException("上传失败：上传路径错误");
        }

        try {
            MinioClient minioClient = minioConfig.minioClient();

            // 文件名称
            String fileName = file.getOriginalFilename();

            // 文件类型
            String suffixName = fileName.substring(fileName.lastIndexOf("."));

            // 验证文件格式
            if (!verifySuffix(suffixName)) {
                return JsonResult.error("上传失败：上传文件不合法");
            }

            // 新文件名
            String objectName = IdUtil.simpleUUID() + suffixName;

            // 文件类型
            String fileType = file.getContentType();

            // 日期路径(当前日期)
            String datePath = DateUtil.format(new Date(), "yyyy/MM/dd");

            // 路径 + 文件对象
            path = path + "/" + datePath + "/" + objectName;

            // 上传
            minioClient.putObject(MinioBucket.MINIO_BUCKET, path, file.getInputStream(), fileType);

            // 获取文件URL
            String url = minioClient.getObjectUrl(MinioBucket.MINIO_BUCKET, path);

            return JsonResult.ok("上传成功").put("url", url).put("name", fileName);
        } catch (Exception e) {
            logger.error("MINIO ERROR", e);
            return JsonResult.error("上传异常");
        }
    }

    /**
     * 获取临时文件路径
     * @param bucket 存储桶
     * @param path 地址
     * @return
     */
    public String getPreSignedObjectUrl(String bucket, String path) {
        if (StrUtil.isBlank(path)) {
            return "";
        }
        try {
            String pathHead = endpoint + "/" + bucket + "/";
            path = StrUtil.removePreAndLowerFirst(path, pathHead);

            MinioClient minioClient = minioConfig.minioClient();
            Map<String, String> map = new HashMap<>();
            return minioClient.getPresignedObjectUrl(Method.GET, bucket, path, 600, map);
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 验证上传文件后缀名是否符合格式要求
     *
     * @param suffix 上传文件后缀名
     * @return true合法 false不合法
     */
    private boolean verifySuffix(String suffix) {
        String[] suffixArr = suffixs.split(",");
        for (String s : suffixArr) {
            if (suffix.toLowerCase().equals(s)) {
                return true;
            }
        }
        return false;
    }

}
